﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace MLRobotic.Tower.Common
{
    public class AsyncWorker<T>
    {
        private Log _log = new Log("AsyncWorker");

        private bool _async = false;
        private int _dropCount = 0;

        private AutoResetEvent _processingTerminated = new AutoResetEvent(true);

        private WorkAcceptedHandler _workAccepted;
        private DoWorkHandler _doWork;

        public delegate void WorkAcceptedHandler(T data);
        public delegate void DoWorkHandler();

        public AsyncWorker(WorkAcceptedHandler workAccepted, DoWorkHandler doWork, bool async)
        {
            _workAccepted = workAccepted;
            _doWork = doWork;
            _async = async;
        }

        public bool TryProcess(T data)
        {
            if (_processingTerminated.WaitOne(0, false))
            {
                if (_dropCount++ < 1)
                {
                    _log.Debug("Drop frame for timing");
                    _processingTerminated.Set();

                    return false;
                }
                
                _log.Debug("Accept frame");
                _dropCount = 0;

                _workAccepted(data);

                if (_async)
                    ThreadPool.QueueUserWorkItem(new WaitCallback(Process));
                else
                    Process(null);

                return true;
            }

            _log.Debug("Drop frame");

            return false;
        }

        private void Process(Object stateInfo)
        {
            try
            {
                _doWork();
            }
            catch (Exception ex)
            {
                _log.Error("Processing failed", ex);
                throw;
            }
            finally
            {
                _processingTerminated.Set();
            }
        }
    }
}
